package auth

import (
	"context"
	"fmt"
	"net/http"
	"strings"

	"laravel-vue-admin/socket/config"

	"github.com/go-redis/redis/v8"
	"github.com/golang-jwt/jwt/v5"
)

var (
	redisClient *redis.Client
	jwtSecret   []byte
	redisPrefix string
)

// Init 初始化认证模块
func Init(cfg *config.Config) error {
	jwtSecret = []byte(cfg.JWT.Secret)
	redisPrefix = cfg.JWT.RedisPrefix

	// 初始化Redis客户端
	redisClient = redis.NewClient(&redis.Options{
		Addr:     fmt.Sprintf("%s:%d", cfg.Redis.Host, cfg.Redis.Port),
		Password: cfg.Redis.Password,
		DB:       cfg.Redis.DB,
	})

	// 测试Redis连接
	ctx := context.Background()
	_, err := redisClient.Ping(ctx).Result()
	if err != nil {
		return fmt.Errorf("Redis连接失败: %w", err)
	}

	return nil
}

// Claims JWT Claims结构
type Claims struct {
	Subject  interface{} `json:"sub"` // Laravel JWT将用户ID存储在sub字段中
	Username string      `json:"username,omitempty"`
	jwt.RegisteredClaims
}

// GetUserID 获取用户ID
func (c *Claims) GetUserID() (int64, error) {
	switch v := c.Subject.(type) {
	case float64:
		return int64(v), nil
	case int64:
		return v, nil
	case int:
		return int64(v), nil
	case string:
		// 如果是字符串，尝试转换为int64
		var id int64
		if _, err := fmt.Sscanf(v, "%d", &id); err == nil {
			return id, nil
		}
		return 0, fmt.Errorf("无法解析用户ID: %v", v)
	default:
		return 0, fmt.Errorf("未知的用户ID类型: %T, value: %v", v, v)
	}
}

// ValidateToken 验证JWT Token
func ValidateToken(tokenString string) (*Claims, error) {
	// 解析Token
	token, err := jwt.ParseWithClaims(tokenString, &Claims{}, func(token *jwt.Token) (interface{}, error) {
		// 验证签名算法
		if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
			return nil, fmt.Errorf("意外的签名方法: %v", token.Header["alg"])
		}
		return jwtSecret, nil
	})

	if err != nil {
		return nil, fmt.Errorf("Token解析失败: %w", err)
	}

	claims, ok := token.Claims.(*Claims)
	if !ok || !token.Valid {
		return nil, fmt.Errorf("Token无效")
	}

	// 获取用户ID
	userID, err := claims.GetUserID()
	if err != nil {
		return nil, fmt.Errorf("获取用户ID失败: %w", err)
	}

	// 从Redis验证Token是否有效
	ctx := context.Background()
	userTokensKey := fmt.Sprintf("%s%d", redisPrefix, userID)
	
	// 检查Token是否在Redis中存在
	exists, err := redisClient.SIsMember(ctx, userTokensKey, tokenString).Result()
	if err != nil {
		return nil, fmt.Errorf("Redis验证失败: %w", err)
	}

	if !exists {
		return nil, fmt.Errorf("Token已失效")
	}

	return claims, nil
}

// ExtractToken 从HTTP请求中提取Token
func ExtractToken(r *http.Request) (string, error) {
	// 从查询参数获取
	token := r.URL.Query().Get("token")
	if token != "" {
		return token, nil
	}

	// 从Header获取
	authHeader := r.Header.Get("Authorization")
	if authHeader != "" {
		parts := strings.SplitN(authHeader, " ", 2)
		if len(parts) == 2 && parts[0] == "Bearer" {
			return parts[1], nil
		}
		return authHeader, nil
	}

	// 从Cookie获取
	cookie, err := r.Cookie("token")
	if err == nil && cookie.Value != "" {
		return cookie.Value, nil
	}

	return "", fmt.Errorf("未找到Token")
}

// AuthenticateWebSocket 验证WebSocket连接
func AuthenticateWebSocket(r *http.Request) (*Claims, error) {
	token, err := ExtractToken(r)
	if err != nil {
		return nil, err
	}

	return ValidateToken(token)
}

// GetUserID 从Token获取用户ID
func GetUserID(tokenString string) (int64, error) {
	claims, err := ValidateToken(tokenString)
	if err != nil {
		return 0, err
	}
	return claims.GetUserID()
}

// Close 关闭Redis连接
func Close() error {
	if redisClient != nil {
		return redisClient.Close()
	}
	return nil
}

